package fi.aalto.cse.T110_5150.P2PClient;

import java.net.*;
import java.util.Enumeration;

public class PeerAddress {
	private static InetAddress localHost;
	
	private InetAddress address;
	private int port;
	private String name;
	
	public static InetAddress getLocalHost() throws SocketException {
		InetAddress inetAddress = null;
		try {
			inetAddress = Inet4Address.getLocalHost();
			if (inetAddress.isSiteLocalAddress()) {
				return inetAddress;
			}
		} catch (UnknownHostException e) {			
		}
		
		for (Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements();) {
			NetworkInterface networkInterface = networkInterfaces.nextElement();
			
			for (Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses(); inetAddresses.hasMoreElements();) {
				InetAddress inetAddress2 = inetAddresses.nextElement(); 
				if ((inetAddress2 instanceof Inet4Address) && inetAddress2.isSiteLocalAddress()) {
					return inetAddress2;
				}
			}				
			
		}
			
		// no site local address
		return inetAddress;
	}

	public PeerAddress(InetAddress address, int port) {
		this.address = address;
		this.port = port;
	}
	
	public static PeerAddress parse(String s) throws P2PException {
		String[] pair = s.split(":", 2);
		
		InetAddress address;
		try {
			address = InetAddress.getByName(pair[0]);
			
			if (localHost == null) {
				localHost = InetAddress.getByName("localhost"); // 127.0.0.1
			}
			
			if (address.equals(localHost)) {
				address = InetAddress.getLocalHost();
			}
		} catch (UnknownHostException e) {
			throw new P2PException(String.format("Unknown host '%s'", pair[0]), e);
		}
		
		int port = P2PHelper.PORT_DEFAULT;
		if (pair.length > 1) {
			port = Integer.parseInt(pair[1]);  
		}
		
		return new PeerAddress(address, port);
	}

	public InetAddress getAddress() {
		return address;
	}
	
	public byte[] getAddressBytes() {
		return address.getAddress();
	}	

	public int getPort() {
		return port;
	}
	
	public void setPort(int port) {
		this.port = port;
		name = null;
	}

	@Override
	public String toString() {
		if (name == null) {
			name = String.format("%s:%04d", address.getHostAddress(), port); 
		}
		return name;
	}

	@Override
	public boolean equals(Object o) {
		return (o instanceof PeerAddress) && address.equals(((PeerAddress) o).address)
				&& port == ((PeerAddress) o).port;
	}
	
	@Override
	public int hashCode() {
		return address.hashCode() ^ port;
	}
}